# -*- coding: utf-8 -*-

from hlm.node import *

from ip.fabrics import ChannelLoadFabric


class NodeMRunner(Node):
    def initialize(self, params: ObjectDict) -> None:
        params.peer_ids: 'List.int'
        # Prepare the ports.
        self.port.chain_in = self.port_channel_receiver(ChannelLoadFabric)
        self.port.chain_out = self.port_channel_sender(ChannelLoadFabric)
        self.port.message_in = self.port_channel_receiver(ChannelLoadFabric)
        self.port.message_out = self.port_channel_sender(ChannelLoadFabric)
        # Create the halt port.
        self.port.halt = self.port_out(bool)
        # Save the pid filter.
        self.reg.pid_filter = 0
        for pid in params.peer_ids:
            self.reg.pid_filter |= (1 << pid)

    tasks = ['task_process_passing',
             'task_halt_detection']

    def task_process_passing(self):
        # Check whether the chain port contains data.
        if not self.port.chain_in.Bus.is_any_empty():
            # Fetch the target Pid.
            self.reg.peer_id = self.port.chain_in.Bus.pid.head()
            # Check whether the peer id is filtered as message.
            if (self.reg.peer_id & self.reg.pid_filter) > 0:
                # Send to message out.
                if not self.port.message_out.Bus.is_any_full():
                    # Passing the data to message out.
                    self.port.message_out.Bus.put_bypass(self.port.chain_in.Bus)
            else:
                # Send to chain out.
                if not self.port.chain_out.Bus.is_any_full():
                    # Passing the data to chain out.
                    self.port.chain_out.Bus.put_bypass(self.port.chain_in.Bus)
        else:
            # Check whether the message port contains data.
            if not self.port.message_in.Bus.is_any_empty():
                # Fetch the target Pid.
                self.reg.peer_id = self.port.message_in.Bus.pid.head()
                # Check whether the peer id is filtered as message.
                if (self.reg.peer_id & self.reg.pid_filter) > 0:
                    # Send to message out.
                    if not self.port.message_out.Bus.is_any_full():
                        # Passing the data to message out.
                        self.port.message_out.Bus.put_bypass(self.port.message_in.Bus)
                else:
                    # Send to chain out.
                    if not self.port.chain_out.Bus.is_any_full():
                        # Passing the data to chain out.
                        self.port.chain_out.Bus.put_bypass(self.port.message_in.Bus)

    def task_halt_detection(self):
        # Put the empty detection data.
        self.port.halt.put(self.port.message_in.Bus.is_any_empty() and
                           self.port.chain_in.Bus.is_any_empty())